package com.ltg.framework.auth.access.filter;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import com.ltg.framework.auth.access.UrlAllow;
import com.ltg.framework.auth.api.AuthAccessHandler;
import com.ltg.framework.auth.api.holder.CurrentUserHolder;
import com.ltg.framework.auth.api.properties.LoginProperties;
import com.ltg.framework.auth.api.vo.AccessResponseVo;
import com.ltg.framework.core.util.http.Result;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @Version 1.0
 * @Author LTG
 * @ClassName AccessFilter
 * @Date 2023/11/17 17:04
 */
@Slf4j
public class AccessFilter implements Filter, Ordered {


    public AccessFilter(LoginProperties loginProperties, AuthAccessHandler authAccessHandler) {
        this.loginProperties = loginProperties;
        this.authAccessHandler = authAccessHandler;

    }

    private final LoginProperties loginProperties;

    private final AuthAccessHandler authAccessHandler;

    // 2.2 创建路径匹配器对象
    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(AntPathMatcher.DEFAULT_PATH_SEPARATOR);

    private ServletContext servletContext;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        servletContext = filterConfig.getServletContext();

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        boolean isPermit = permitUrl(request);
        if (isPermit) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        String token = this.getToken(request);
        if (!org.springframework.util.StringUtils.hasLength(token)) {
            returnNoLogin(servletResponse);
            return;
        }
        AccessResponseVo accessResponseVo = authAccessHandler.handleAccess(token);
        //传入SsoContext
        CurrentUserHolder.setCurrentUser(accessResponseVo.getAuthInfo());
        filterChain.doFilter(servletRequest, servletResponse);
    }

    private String getToken(HttpServletRequest request) {
        String firstToken = request.getHeader("Authorization");
        if (CharSequenceUtil.isBlank(firstToken)) {
            firstToken = request.getParameter("token");
        } else {
            if (CharSequenceUtil.startWith(firstToken, "Bearer ")) {
                firstToken = CharSequenceUtil.subSuf(firstToken, 7);
            }
        }
        return firstToken;
    }


    /**
     * @param urls       a
     * @param requestURI a
     * @return 判断某个请求是否在不登录的时候就可以放行
     */

    private boolean permitUrl(HttpServletRequest request) {
        // 过滤路径
        String path = request.getRequestURI();

        // 默认配置
        List<String> urlAllowList = UrlAllow.getUrlAllowList();
        for (String url : urlAllowList) {
            // 匹配 本次请求的requestURI  是否符合 url
            if (ANT_PATH_MATCHER.match(url, path)) {
                return true;
            }
        }

        // 自定义配置
        List<String> filterExcludeUrl = loginProperties.getFilterExcludeUrl();
        for (String url : filterExcludeUrl) {
            if (ANT_PATH_MATCHER.match(url, path)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 返回未登录的错误信息
     *
     * @param response ServletResponse
     */
    private void returnNoLogin(ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        ServletOutputStream outputStream = httpServletResponse.getOutputStream();
        // 设置返回401 和响应编码
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.setContentType("Application/json;charset=utf-8");
        // 构造返回响应体

        Result<String> result = Result.error(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
        String resultString = JSONUtil.toJsonStr(result);
        outputStream.write(resultString.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public void destroy() {
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
